/*
 * 学霸型红外遥控器 
 * 太极创客 http://www.taichi-maker.com/
 * Ver. 1.2 - 01/07/2017
 * =====================功能说明=====================
 * 利用Arduino开发板记录并“重放”红外遥控信号
 * 用户可以使用家中控制电器用的红外遥控器对准本装置的
 * 红外接收器，本装置可将接收到的红外遥控信号记录至EEPROM。
 * 当用户按下"发射"按键时，红外LED会发射记录的红外遥控信号
 * 从而控制家中电器。
 * 
 * 本示例程序主要内容借鉴Ken Shirriff 的 IRremote 库示例程序IRrecord。
 * 
 * 本程序基于Ken Shirriff开发的IRremote库。如需获得该库文件
 * 可前往以下网址获得：
 * http://arcfn.com   （Ken Shirriff个人博客）
 * http://www.taichi-maker.com/   （太极创客官网）
 * 
 * =====================电路连接======================
 * 红外接收器 1838B OUT 引脚 --- Arduino Uno 引脚 11
 *     红外发射 LED 正极     --- Arduino Uno 引脚  3
 *         按键开关          --- Arduino Uno 引脚 12
 *         
 *  如需获得详细电路连接说明图，请参阅太极创客网站:
 *  http://WWW.TAICHI-MAKER.COM
 * 
 * 此示例程序为配合太极创客制作的
 * 《零基础入门学用ARDUINO教程-智能应用篇》使用
 * 版本更新说明
 * V1.1 使用put get来 进行EEPROM存取
 * V1.2 针对IRrecord代码进行优化
 */
 
#include <IRremote.h>
#include <EEPROM.h>
 
#define codeValueEAddr    1  // 存放红外信号数值EEPROM地址  
#define RECV_PIN 11          // 红外接收器 OUT 引脚 --- Arduino 引脚11
#define BUTTON_PIN 12               // 按键开关 --- Arduino 引脚12
#define STATUS_PIN LED_BUILTIN      // 状态显示LED --- 开发板内置LED
 
IRrecv irrecv(RECV_PIN);   // 红外遥控接收器对象
IRsend irsend;             // 红外遥控发射对象
 
void setup() {
  Serial.begin(9600);
  irrecv.enableIRIn(); // 启动红外接收
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(STATUS_PIN, OUTPUT);
  delay(10);
  loadEepromValues();  // 从EEPROM中读取红外信号信息（具体信息请见函数部分）
}
 
// 红外信号存储变量
unsigned long codeValue; // 存放红外信号数值(如果不是raw型)
int codeLen; 

// 记录收到的红外信号
void storeCode(unsigned long rs) {
  Serial.println("Received unknown code, saving as raw");  
  Serial.println(rs, HEX); //输出信号数值
  codeValue = rs;
  writeEepromVal();  //将收到的信号信息储存于eeprom
}
 
// 发射红外信号
void sendCode(int repeat) {
  irsend.sendRaw(codeValue, codeLen, 38);
  Serial.println("Sent raw");
  //Serial.println(rawCodes, HEX);
}
 
int lastButtonState;   // 此变量用于判断发射红外信号的按键开关所处的状态
 
void loop() {
  
  int buttonState = !digitalRead(BUTTON_PIN);           // 读取当前的按键开关状态（检查用户是否按下了按键开关）
  if (lastButtonState == HIGH && buttonState == LOW) {  // 如果按键开关是被按下后再抬起的
    
    Serial.println("Released");                         // 通过串口监视器输出"按键抬起"
    irrecv.enableIRIn();                                // 启动红外接收器信号接收
  } f:\code_mine\arduino_shiyan\17jidianqimokuai\17jidianqimokuai.ino                                                    
 
  if (buttonState) {                                    // 如果按键开关处于被按下的状态
    
    Serial.println("Pressed, sending");                 // 通过串口监视器输出"按键按下"
    digitalWrite(STATUS_PIN, HIGH);                     // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号（点亮LED）
    sendCode(lastButtonState == buttonState);           // 更新按键开关状态变量
    digitalWrite(STATUS_PIN, LOW);                      // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号（熄灭LED）
    delay(50);                                          // 信号发射间歇
    
  } else if (irrecv.decode()) {                 // 如果按键开关处于没有被按下的状态，则实时检查红外接收器并对接收到的信号进行解码
                                                        // 如果接收到的红外信号可以通过decode函数成功解码
    unsigned long result = irrecv.decodedIRData.decodedRawData;  
    
    digitalWrite(STATUS_PIN, HIGH);                     // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号（点亮LED）
    storeCode(result);                                // 将解码的红外信号信息进行储存（非EEPROM储存）
    irrecv.resume();                                    // 恢复红外接收器
    digitalWrite(STATUS_PIN, LOW);                      // 闪烁状态显示红外LED告知用户当前"学霸遥控器"正在发射红外信号（熄灭LED）
  }
  lastButtonState = buttonState;                        // 更新按键开关状态变量
}
 
// 通过EEPROM读取红外信号信息
// 每次Arduino通电后，都会从EEPROM中读取存储的红外信号信息。
// 从而确保"学霸遥控器"在断电后依然可以保持上一次运行时所存储的
// 红外信号信息。
void loadEepromValues(){
  EEPROM.get(codeValueEAddr, codeValue);
}
 
// 将红外信号信息储存于EEPROM
// 每一次"学霸遥控器"接收到新的红外遥控信号
// 都将最新接收的红外遥控器储存于EEPROM
// 从而确保信号信息不会因为Arduino断电而丢失
void writeEepromVal(){
   EEPROM.put(codeValueEAddr, codeValue);
   delay(10);
}